package cn.edu.njust.aio;

import cn.edu.njust.EchoClient;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.ExecutionException;

@Slf4j
public class AioEchoClient implements EchoClient {
    private AsynchronousSocketChannel channel;

    private static String recv(AsynchronousSocketChannel socketChannel) {
        ByteArrayOutputStream bufferStream = new ByteArrayOutputStream();
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        try {
            // 同步读
            while (((socketChannel.read(buffer)).get() > 0)) {
                buffer.flip();
                bufferStream.write(buffer.array(), 0, buffer.limit());
            }

            return bufferStream.toString();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        return null;
    }

    private void send(AsynchronousSocketChannel socketChannel, String message) {

        try {
            // 同步写
            socketChannel.write(ByteBuffer.wrap(message.getBytes())).get();
            // 发完消息记得关闭输出，否则会导致服务端read一直阻塞！(这里不采用拆包机制)
            socketChannel.shutdownOutput();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void connect(int port) {
        try {
            channel = AsynchronousSocketChannel.open();
            // 同步等待连接成功
            // 这里必须加上hostname，否则会报错！！！
            channel.connect(new InetSocketAddress("localhost", port)).get();
            log.info("连接服务器成功");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String echo(String message) {

        send(channel, message);
        log.info("向服务端发送{}", message);

        return recv(channel);
    }

    @Override
    public void close() {

    }
}
